#pragma once
#include "InetAddr.hpp"
#include "log.hpp"

namespace SocketModule
{
    int mybacklog = 17;
    using namespace LogModule;
    // 虚基类
    class Socket
    {
    public:
        virtual void socketordie() = 0;
        virtual void bindordie(uint16_t port) = 0;
        virtual void listenordie() = 0;
        virtual int acceptordie(InetAddr *client) = 0;
        virtual void Close() = 0;
        virtual int getfd() = 0;
        virtual int Recive(std::string *buffer) = 0;
        virtual int Send(std::string pacakge) = 0;
        virtual int Connect(const std::string &server_ip, uint16_t port) = 0;
        void BuildTcpSocketMethod(uint16_t port)
        {
            socketordie();
            bindordie(port);
            listenordie();
        }
        void BuildTcpClientSocketMethod()
        {
            socketordie();
        }
    };

    class TcpSocket : public Socket
    {
    public:
        TcpSocket() {}
        TcpSocket(int sockfd) : _sockfd(sockfd) {}
        ~TcpSocket()
        {
        }
        int getfd() override
        {
            return _sockfd;
        }
        void socketordie() override
        {
            int n = socket(AF_INET, SOCK_STREAM, 0);
            if (n < 0)
            {
                LOG(LogLevel::DEBUG) << "socket error";
                exit(SOCKET_ERR);
            }
            LOG(LogLevel::DEBUG) << "socker success";
            _sockfd = n;
            int opt = 1;
            setsockopt(n, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
        }
        void bindordie(uint16_t port) override
        {
            InetAddr local(port);
            int n = bind(_sockfd, local.NetAddrPtr(), local.NetAddrLen());
            if (n < 0)
            {
                LOG(LogLevel::DEBUG) << "bind error";
                exit(BIND_ERR);
            }
            LOG(LogLevel::DEBUG) << "bind success";
        }
        int Recive(std::string *buffer) override
        {
            char buff[4096 * 2];
            int n = ::recv(_sockfd, buff, sizeof(buff) - 1, 0);
            if (n > 0)
            {
                buff[n] = 0;
            }
            *buffer += buff;
            return n;
        }
        int Send(std::string pacakge) override
        {
            int n = send(_sockfd, pacakge.c_str(), pacakge.size(), 0);
            return n;
        }
        void listenordie() override
        {
            int n = listen(_sockfd, mybacklog);
            if (n < 0)
            {
                LOG(LogLevel::DEBUG) << "listen error";
                exit(BIND_ERR);
            }
            LOG(LogLevel::DEBUG) << "listen success";
        }
        void Close() override
        {
            close(_sockfd);
        }
        // 输出型参数吧客户端信息带出去
        // 返回值设置为Tcpsocket这样我们就可以继续在类内添加方法如果后续需要实现
        int acceptordie(InetAddr *client) override
        {
            sockaddr_in peer;
            socklen_t len = sizeof(peer);

            int n = accept(_sockfd, CONV(peer), &len);
            if (n < 0)
            {
                LOG(LogLevel::WARNING) << "accept warning" << strerror(errno);

                return -1;
            }
            LOG(LogLevel::DEBUG) << "accept success";
            sleep(1);
            client->SetAddr(peer);
            return n;
        }
        int Connect(const std::string &server_ip, uint16_t port) override
        {
            InetAddr server(server_ip, port);
            return ::connect(_sockfd, server.NetAddrPtr(), server.NetAddrLen());
        }

    private:
        int _sockfd;
    };
}